package com.v9.main.controller.flow;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.v9.common.dto.IdDto;
import com.v9.common.dto.PageInfoDto;
import com.v9.common.dto.TreeNodeDto;
import com.v9.common.exception.BizException;
import com.v9.common.web.AbstractController;
import com.v9.flow.domain.FlowBizType;
import com.v9.flow.domain.FlowInfo;
import com.v9.flow.domain.FlowSponsor;
import com.v9.flow.domain.model.SponsorTypeEnum;
import com.v9.flow.mapper.FlowSponsorMapper;
import com.v9.flow.service.FlowBizTypeService;
import com.v9.flow.service.FlowInfoService;
import com.v9.system.domain.DeptInfo;
import com.v9.system.domain.RoleInfo;
import com.v9.system.domain.RoleType;
import com.v9.system.service.DeptInfoService;
import com.v9.system.service.RoleInfoService;
import com.v9.system.service.RoleTypeService;
import com.v9.system.service.UserInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.data.domain.Page;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author lunshi
 */
@RestController
@Tag(name = "工作流列表管理")
@RequestMapping(
        value = {"/fl/flow/info"},
        method = {RequestMethod.POST}
)
@Slf4j
public class FlowController extends AbstractController {
    @Resource
    private FlowInfoService flowInfoService;
    @Resource
    private FlowBizTypeService flowBizTypeService;

    @Resource
    private RoleInfoService roleInfoService;

    @Resource
    private RoleTypeService roleTypeService;
    @Resource
    private DeptInfoService deptInfoService;
    @Resource
    private FlowSponsorMapper flowSponsorMapper;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private Snowflake snowflake;

    @RequestMapping({"list"})
    @Operation(summary = "列表")
    public Page<FlowResultDto> list(@RequestBody PageInfoDto dto) {
        Page<FlowInfo> results = flowInfoService.queryByPage(new FlowInfo(), dto.getPageable());
        Page<FlowResultDto> clone = clone(FlowResultDto.class, results);
        clone.getContent().forEach(item -> {
            FlowBizType byId = flowBizTypeService.findById(item.getBizTypeId());
            if (byId != null) {
                item.setBizTypeName(byId.getName());
            }
        });
        return clone;
    }

    @RequestMapping({"deptUserTree"})
    @Operation(summary = "部门用户树")
    public List<TreeNodeDto> deptUserTree() {
        return deptInfoService.deptUserTree();
    }

    @RequestMapping({"roleListTree"})
    @Operation(summary = "角色树")
    public List<TreeNodeDto> roleListTree() {
        List<TreeNodeDto> results = new ArrayList<>();
        List<RoleType> roleTypes = roleTypeService.queryAll();
        List<RoleInfo> roleInfos = roleInfoService.queryAll();
        roleTypes.forEach(item -> {
            TreeNodeDto e = new TreeNodeDto();
            e.setLabel(item.getName());
            e.setId(item.getId().toString());
            e.setType(1);
            List<RoleInfo> collect = roleInfos.stream().filter(role -> role.getRoleTypeId().equals(item.getId())).collect(Collectors.toList());
            e.setChildren(new ArrayList<>());
            collect.forEach(roleItem -> {
                TreeNodeDto e1 = new TreeNodeDto();
                e1.setType(2);
                e1.setId(roleItem.getId().toString());
                e1.setLabel(roleItem.getName());
                e.getChildren().add(e1);
            });
            results.add(e);
        });
        return results;
    }

    @RequestMapping({"deployment"})
    @Operation(summary = "部署")
    public void deployment(@RequestBody IdDto dto) {
        flowInfoService.deployment(dto.getId());
    }

    @RequestMapping({"changeDepStatus"})
    @Operation(summary = "修改部属状态")
    public void changeDepStatus(@RequestBody IdDto dto) {
        FlowInfo info = flowInfoService.findById(dto.getId());
        if (info.getDepStatus().equals(Boolean.FALSE)) {
            flowInfoService.deployment(dto.getId());
            flowInfoService.save(dto.getId(), "depStatus", !info.getDepStatus());
            return;
        }
        if (info.getDepStatus().equals(Boolean.TRUE)) {
            flowInfoService.save(dto.getId(), "depStatus", !info.getDepStatus());
        }
    }

    @RequestMapping({"insert"})
    @Operation(summary = "新增")
    public void insert(@RequestBody InsertDto dto) {
        try {
            FlowInfo clone = clone(FlowInfo.class, dto);
            File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "default.bpmn20.xml");
            String s = IOUtils.toString(file.toURI(), "utf-8");
            s = s.replace("{code}", dto.getCode());
            s = s.replace("{code}", dto.getCode());
            s = s.replace("{name}", dto.getName());
            clone.setContent(s);
            clone.setDepStatus(false);
            flowInfoService.insert(clone);
        } catch (Exception e) {
            log.error("FlowController.insert.error", e);
            throw new BizException("新增流程失败");
        }
    }

    @RequestMapping({"save"})
    @Operation(summary = "修改")
    public void save(@RequestBody SaveFlowDto dto) {
        FlowInfo info = flowInfoService.findById(dto.getId());
        if (info == null) {
            throw new BizException("非法操作");
        }
        info = clone(FlowInfo.class, dto);
        List<FlowSponsor> list=new ArrayList<>();
        dto.sponsorList.forEach(item->{
            FlowSponsor e = new FlowSponsor();
            e.setType(item.getType());
            e.setFlowId(dto.getId());
            e.setRefId(item.getRefId());
            list.add(e);
        });
        flowInfoService.save(info,list);
    }

    @RequestMapping({"view"})
    @Operation(summary = "查看")
    public SaveFlowDto view(@RequestBody IdDto dto) {
        FlowInfo info = flowInfoService.findById(dto.getId());
        QueryWrapper<FlowSponsor> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id",dto.getId());
        List<FlowSponsor> flowSponsors = flowSponsorMapper.selectList(queryWrapper);
        List<FlowSponsorDto> dtoList=clone(FlowSponsorDto.class,flowSponsors);
        dtoList.forEach(item->{
            if(item.type==SponsorTypeEnum.role){
                long id = Long.parseLong(item.refId);
                item.setLabel(roleInfoService.findById(id).getName());
            }
            if(item.type==SponsorTypeEnum.dept){
                long id = Long.parseLong(item.refId);
                DeptInfo deptInfo = deptInfoService.findById(id);
                item.setLabel(deptInfo.getName());
            }
            if(item.type==SponsorTypeEnum.user){
                item.setLabel(userInfoService.findById(item.refId).getRealName());
            }
        });
        SaveFlowDto result = clone(SaveFlowDto.class, info);
        result.setSponsorList(dtoList);
        return result;
    }

    @RequestMapping({"del"})
    @Operation(summary = "删除")
    public void del(@RequestBody IdDto dto) {
        flowInfoService.remove(dto.getId());
    }

    @RequestMapping({"viewFlowContent"})
    @Operation(summary = "查询流程详情数据")
    public String viewFlowContent(@RequestBody IdDto dto) {
        return flowInfoService.findById(dto.getId()).getContent();
    }

    @RequestMapping({"saveFlowContent"})
    @Operation(summary = "保存流程数据")
    public void saveFlowContent(@RequestBody SaveFlowDetailDto dto) {
        flowInfoService.saveContent(dto.getId(), dto.getData());
    }

    @Data
    public static class SaveFlowDetailDto {
        private Long id;
        private String data;
    }

    @Data
    @Schema(description = "保存数据")
    public static class SaveDto {
        @Schema(description = "id")
        private String id;
        @Schema(description = "数据")
        private String data;
    }

    @Data
    public static class InsertDto {
        @Schema(description = "名称")
        @NotEmpty
        @Length(max = 32)
        private String name;
        @NotEmpty
        @Length(max = 150)
        private String icon;
        @NotEmpty
        @Length(max = 32)
        private String code;
        @Schema(description = "业务类型id")
        @NotNull
        private Long bizTypeId;
        @Schema(description = "分组id")
        @NotNull
        private Long groupId;
        @Schema(description = "备注")
        @Length(max = 64)
        private String remark;
        @Schema(description = "执行者")
        private List<FlowSponsorDto> sponsorList;
    }

    @Data
    public static class FlowSponsorDto {
        private SponsorTypeEnum type;
        private String refId;
        private Long flowId;
        private String label;

    }

    @Data
    public static class SaveFlowDto {
        @Schema(description = "id")
        private Long id;
        @Schema(description = "名称")
        @Length(max = 32)
        private String name;
        @NotEmpty
        @Length(max = 32)
        private String code;
        @NotEmpty
        @Length(max = 150)
        private String icon;
        @Schema(description = "分组Id")
        @NotNull
        private Long groupId;
        @Schema(description = "流程业务类型")
        @NotNull
        private Long bizTypeId;
        @Schema(description = "备注")
        @Length(max = 64)
        private String remark;
        private String content;
        @Schema(description = "发布状态")
        private Boolean depStatus;
        @Schema(description = "执行者")
        private List<FlowSponsorDto> sponsorList;

    }

    @Data
    public static class FlowResultDto {
        @Schema(description = "id")
        private Long id;
        @Schema(description = "组id")
        private Long groupId;
        @Schema(description = "名称")
        private String name;
        @Schema(description = "编码")
        private String code;
        @Schema(description = "图标")
        private String icon;
        @Schema(description = "流程业务类型")
        private Long bizTypeId;
        @Schema(description = "流程业务类型")
        private String bizTypeName;
        @Schema(description = "备注")
        private String remark;
        @Schema(description = "创建时间")
        private Date createTime;
        @Schema(description = "发布状态")
        private Boolean depStatus;

    }
}
